package Stana.kmeansSeqPatternMining;

import java.util.ArrayList;
import java.util.List;

import Stana.hierarchicalClustering.PriceQuantityCluster;
import Stana.hierarchicalClustering.PriceQuantityItem;


public class AlgoSeqHierarchicalClustering extends AbstractAlgoClustering {
	
	private final double threshold;

	public AlgoSeqHierarchicalClustering(double threshold) {
		this.threshold = threshold;
	}
	
	public List<PriceQuantityCluster> runAlgorithm(List<PriceQuantityItem> items) {
		List<PriceQuantityCluster> clusters = new ArrayList<PriceQuantityCluster>();
		
		// (1) Initialize all items as clusters
		for(PriceQuantityItem item : items){
			PriceQuantityCluster cluster = new PriceQuantityCluster(item);
			clusters.add(cluster);
		}
		
		// (2) Loop to combine the two closest clusters into a bigger cluster
		//     until no clusters can be combined.
		boolean wasAMerge = false;
		do{
			wasAMerge = mergeTheClosestCluster(clusters, threshold);
		} while(wasAMerge);
		
		// Calculate min and max 
		for(PriceQuantityCluster cluster : clusters){
			cluster.computeHigherAndLowerQuantity();
			cluster.computeHigherAndLowerPrice();
		}
		
		return clusters;
	}

	private boolean mergeTheClosestCluster(List<PriceQuantityCluster> clusters, double threshold) {
		PriceQuantityCluster clusterToMerge1 = null;
		PriceQuantityCluster clusterToMerge2 = null;
		double minClusterPrice = Integer.MAX_VALUE;
		double minClusterQuantity = Integer.MAX_VALUE;
		
		// find the two closest cluster with quantity and quantity < threshold
		for(int i=0; i< clusters.size(); i++){
			for(int j= i+1; j< clusters.size(); j++){
				double quantity = medianQuantity(clusters.get(i), clusters.get(j));
				if(quantity < minClusterQuantity && quantity < threshold){
					minClusterQuantity = quantity;
					clusterToMerge1 = clusters.get(i);
					clusterToMerge2 = clusters.get(j);
				}
			}
		}	
//		// find the two closest cluster with price > threshold
//		for(int i=0; i< clusters.size(); i++){
//			for(int j= i+1; j< clusters.size(); j++){
//				double price = medianPrice(clusters.get(i), clusters.get(j));
//				if(price < minClusterPrice && price < threshold){
//					minClusterPrice = price;
//					clusterToMerge1 = clusters.get(i);
//					clusterToMerge2 = clusters.get(j);
//				}
//			}
//		}	
		
		// if no close clusters were found, return false
		if(clusterToMerge1 == null) {
			return false;
		}
		
		// else, merge the two closest clusters
		clusterToMerge1.addItemsFromCluster(clusterToMerge2);
		clusterToMerge1.recomputeClusterMedianPrice();
		clusterToMerge1.recomputeClusterMedianQuantity();
		clusters.remove(clusterToMerge2);
		
		return true;
	}
	
	private double medianPrice(PriceQuantityCluster cluster1, PriceQuantityCluster cluster2){
		return Math.abs(cluster1.getMedianPrice() - cluster2.getMedianPrice());
	}
	private double medianQuantity(PriceQuantityCluster cluster1, PriceQuantityCluster cluster2){
	return Math.abs(cluster1.getMedianQuantity() - cluster2.getMedianQuantity());
	}
	
}
